/*the desk calculator: 功能是对输入的表达式求值。
 1.表达式中的 
 -、*、/、取负(-) 和赋值(=)，可以加括号，遵循四则运算规则
 2.预先定义的常量名为pi和e，对应值为3.1415926、2.7182818
 3.未赋值变量的值为0
 4.对于输入的每个表达式，输出其值
 5.多个表达式可以放在同一行，用";"分隔 
   
表达式示例：
2+3;
2+3*4;x=5;2*x*pi;(2+x)*3-4/5 
*/

//page:109
#include <iostream>
#include <string>
using namespace std;
enum Token_value {
	NAME, NUMBER, END,
	PLUS = '+', MINUS = '-', MUL = '*', DIV = '/',
	PRINT = ';', ASSIGN = '=', LP = '(', RP = ')'
};

double expr(bool get);      //表达式分析开始以及处理'+'、'-'运算（符）
double term(bool get);		//处理'*'、'/'运算（符）
double prim(bool get);      //表达式的基本项 
double error(const string&);//出错处理 
Token_value get_token();	//从输入序列中读取一个记号（符号）

map<string, double> table;  //符号表: "常量（变量）名-值"   
Token_value curr_tok = PRINT; //全局变量curr_tok表示当前符号（记号）
int no_of_errors; 	//全局变量no_of_errors表示错误个数 


//page:109
double expr(bool get)		//表达式分析开始以及处理'+'、'-'运算（符）
{
	double left = term(get);		//left表示'+'、'-'的左边结果 

	for (;;)  						//无穷循环 
		switch (curr_tok) {
		case PLUS:
			left += term(true);//调用term()得到'+'的右边结果，'+'运算后结果保存在left中 
			break;
		case MINUS:
			left -= term(true);
			break;
		default:
			return left;
		}
}

//page:110
double term(bool get)		//处理'*'、'/'运算（符）
{

	double left = prim(get);		//left表示'*'、'/'的左边结果 

	for (;;)
		switch (curr_tok) {
		case MUL:
			left *= prim(true);//调用term()得到'*'的右边结果，'*'运算后结果保存在left中
			break;
		case DIV:				//除数不能为0 
			if (double d = prim(true)) {
				left /= d;
				break;
			}
			return error("divide by 0");
		default:
			return left;
		}
}

//page:115
double error(const string& s)
{
	no_of_errors++;
	cerr << "error: " << s << "\n";
	return 1;
}

//page:111
double number_value;  //全局变量number_value表示从表达式中取到的数值常量，如:25,25.5,.25 
string string_value;  //全局变量string_value表示从表达式中取到(具有独立含义)的字符串

double prim(bool get) //处理表达式中的基本项,如：25,pi,x,-25,-pi,-x,(pi*2+3.5) 
{
	if (get) get_token();	//调用get_token()获取一个记号（符号）给curr_tok 

	switch (curr_tok) {
	case NUMBER: {		//浮点数常量  
		double v = number_value;
		get_token();
		return v;
	}
	case NAME: {		//命名常量或变量的名字 
		double& v = table[string_value];  //已定义的命名常量 
		if (get_token() == ASSIGN)		//名字后跟赋值运算符，是变量名 
			v = expr(true); 			//获得变量的值(也是一个表达式)
		return v;
	}
	case MINUS: {		//取负
		return -prim(true);
	}
	case LP: {		//左括号 
		double e = expr(true);
		if (curr_tok != RP) return error(") expected");
		get_token();  //扔掉')'
		return e;
	}
	default:
		return error("primary expected");
	}
}

//page:112-115
Token_value get_token()	//从输入序列中逐个字符分析，读取一个记号（符号）给curr_tok 
{
	char ch = 0;
	cin.get(ch) ;       //从输入序列取一个字符
	while (ch != '\n' && isspace(ch)) {   //属于非换行字符的其他空白字符是取下一个字符
		if (!cin.get(ch)) return curr_tok = END;    //输入结束
	}

	switch (ch) {
	case 0:  return END; 
	case ';':
	case '\n': return curr_tok = PRINT;
	case '*':
	case '/':
	case '+':
	case '-':
	case '(':
	case ')': 
	case '=': return curr_tok = Token_value(ch);
	case '0': case '1': case '2':case '3':case '4':
	case '5': case '6': case '7':case '8':case '9':
	case '.': { //NUMBER
		cin.putback(ch);
		cin >> number_value;
		return curr_tok = NUMBER;
	}
	default: {  //NAME(字母开头的字母数字串),NAME=,or error  Page115

		if (isalpha(ch)) {
			string_value = ch;
			while (cin.get(ch) && isalnum(ch))
				string_value.push_back(ch);
			cin.putback(ch);
			return curr_tok = NAME;
		}
		error("bad token");
		return curr_tok = PRINT;
	}
	}
}

 
int main()
{
	table["pi"] = 3.1415926;
	table["e"] = 2.7172818;

	while (cin) {
		get_token();
		if (curr_tok == END) 	break;
		if (curr_tok == PRINT) continue;
		cout <<"output: "<< expr(false) << endl;
	}

	return no_of_errors;
}




